#pragma  once
#pragma warning (disable : 4251 )
#include "Weak_ptr.h"


// implementation of smart ptrs can be changed
#ifdef LE_BOOST_SHARED_PTR
#include "Shared_ptr_Impl_boost.h"
#else
#include "Shared_ptr_Impl_own.h"
#endif

namespace Boon
{


template<class T>
class Shared_ptr
{
	template<typename T>
	friend class Boon::Weak_ptr;
	template<typename Y>
	friend class Shared_ptr;
public:
	Shared_ptr();
	Shared_ptr( const Boon::Shared_ptr<T>& o );
	template<typename Y> Shared_ptr( const Shared_ptr<Y>& o );
	Shared_ptr( const Boon::Weak_ptr<T>& o );
	Shared_ptr( T* o );


	T*							Get() const;
	T*							operator&() const;
	T&							operator*() const;
	const Shared_ptr<T>&		operator=( const Shared_ptr<T>& rhs );
	T*							operator->() const;
	unsigned int				UseCount() const;
	operator bool() const;

private:

	PimplImplementation::Shared_ptr_Impl<T>		m_Implementation; /*!< Implementation of this class hidden in namespace PimplImplementation */

};

#pragma region Implementation Forwarding to Shared_ptr_Impl-Class
template<class T>
Boon::Shared_ptr<T>::Shared_ptr()
	: m_Implementation()
{

}

template<class T>
Boon::Shared_ptr<T>::Shared_ptr( const Boon::Shared_ptr<T>& o )
	: m_Implementation( o.m_Implementation )
{

}

template<class T>
template<typename Y>
Boon::Shared_ptr<T>::Shared_ptr( const Shared_ptr<Y>& o )
	: m_Implementation( o.m_Implementation )
{

}


template<class T>
Boon::Shared_ptr<T>::Shared_ptr( const Boon::Weak_ptr<T>& o )
	: m_Implementation( o.m_Implementation )
{

}

template<class T>
Boon::Shared_ptr<T>::Shared_ptr( T* o )
	: m_Implementation( o )
{
	
}

template<class T>
const Boon::Shared_ptr<T>& Boon::Shared_ptr<T>::operator=( const Boon::Shared_ptr<T>& rhs )
{
	m_Implementation = rhs.m_Implementation;
	return *this;
}

template<class T>
T& Boon::Shared_ptr<T>::operator*() const
{
	return *m_Implementation.Get();
}


template<class T>
Boon::Shared_ptr<T>::operator bool() const
{
	return m_Implementation.Get() != nullptr;
}


template<class T>
T* Boon::Shared_ptr<T>::operator&() const
{
	return m_Implementation.Get();
}

template<class T>
T* Boon::Shared_ptr<T>::Get() const
{
	return m_Implementation.Get();
}

template<class T>
T* Boon::Shared_ptr<T>::operator->() const
{
	return m_Implementation.Get();
}

template<class T>
unsigned int Boon::Shared_ptr<T>::UseCount() const
{
	return m_Implementation.UseCount();
}


#pragma endregion

}
